package com.ruoyi.system.service.impl;

import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.system.domain.RedisDataInfo;
import com.ruoyi.system.service.ISysRedisKeyService;
import com.ruoyi.system.service.ISysRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author wjialong
 */
@Service
public class SysRedisKeyServiceImpl implements ISysRedisKeyService {
    @Autowired
    ISysRedisService redisService;

    @Override
    public TableDataInfo getKeyList(RedisDataInfo redisDataInfo, String pattern, String sort,
                                    Integer pageNum, Integer pageSize) {
        StringRedisTemplate redisTemplate = redisService.getRedisTemplate(redisDataInfo);
        List<RedisDataInfo> keyInfos = new ArrayList<>(10);
        int startIndex = (pageNum - 1) * pageSize;
//        Integer endIndex = startIndex + pageSize;
        // 创建比较器
        Comparator<String> comparator = (o1, o2) -> {
            if (sort == null) {
                return 0;
            }
            if ("descend".equals(sort)) {
                return o2.compareTo(o1);
            }
            if ("ascend".equals(sort)) {
                return o1.compareTo(o2);
            }
            return 0;
        };
        // 请求获取keys
        Set<String> keys = redisTemplate.keys(pattern);
        String total = String.valueOf(keys.size());
        keys.stream().sorted(comparator).skip(startIndex).limit(pageSize).forEach(key -> {
            RedisDataInfo keyInfo = new RedisDataInfo();
            DataType type = redisTemplate.type(key);
            // List需要返回size
            if (type == DataType.LIST) {
                ListOperations<String, String> opsForList = redisTemplate.opsForList();
                keyInfo.setSize(opsForList.size(key));
            }
            keyInfo.setKey(key);
            keyInfo.setType(type);
            keyInfo.setTtl(redisTemplate.getExpire(key));
            keyInfos.add(keyInfo);
        });
        redisTemplate.getConnectionFactory().getConnection().close();

        // 构建返回数据
        TableDataInfo tableDataInfo = new TableDataInfo(keyInfos, Integer.parseInt(total));
        tableDataInfo.setCode(HttpStatus.SUCCESS);
        tableDataInfo.setMsg("查询成功");
        return tableDataInfo;
    }

    @Override
    public void getKeyInfo(RedisDataInfo redisDataInfo) {
        StringRedisTemplate redisTemplate = redisService.getRedisTemplate(redisDataInfo);
        // 设置ttl
        redisDataInfo.setTtl(redisTemplate.getExpire(redisDataInfo.getKey()));
        // 根据分类设置数据
        redisDataInfo.setType(redisTemplate.type(redisDataInfo.getKey()));
        if (Objects.requireNonNull(redisDataInfo.getType()) == DataType.LIST) {
            ListOperations<String, String> opsForList = redisTemplate.opsForList();
            redisDataInfo.setSize(opsForList.size(redisDataInfo.getKey()));
        }
        redisTemplate.getConnectionFactory().getConnection().close();
    }

    @Override
    public boolean addKey(RedisDataInfo redisDataInfo) {
        StringRedisTemplate redisTemplate = redisService.getRedisTemplate(redisDataInfo);
        Boolean exist = redisTemplate.hasKey(redisDataInfo.getKey());
        if (Boolean.TRUE.equals(exist)) {
            redisTemplate.getConnectionFactory().getConnection().close();
            return false;
        }
        switch (redisDataInfo.getType()) {
            case STRING:
                ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
                opsForValue.set(redisDataInfo.getKey(), (String) redisDataInfo.getValue());
                break;
            case LIST:
                ListOperations<String, String> opsForList = redisTemplate.opsForList();
                opsForList.leftPush(redisDataInfo.getKey(), (String) redisDataInfo.getValue());
                break;
            case HASH:
                HashOperations<String, Object, Object> opsForHash = redisTemplate.opsForHash();
                List<String> list = (List<String>) redisDataInfo.getValue();
                opsForHash.put(redisDataInfo.getKey(), list.get(0), list.get(1));
                break;
            case SET:
                SetOperations<String, String> opsForSet = redisTemplate.opsForSet();
                opsForSet.add(redisDataInfo.getKey(), (String) redisDataInfo.getValue());
                break;
            case ZSET:
                List<String> list1 = (List<String>) redisDataInfo.getValue();
                ZSetOperations<String, String> opsForZSet = redisTemplate.opsForZSet();
                opsForZSet.add(redisDataInfo.getKey(), list1.get(0), Double.parseDouble(list1.get(1)));
        }
        redisTemplate.getConnectionFactory().getConnection().close();
        return true;
    }

    @Override
    public void deleteKey(RedisDataInfo redisDataInfo) {
        StringRedisTemplate redisTemplate = redisService.getRedisTemplate(redisDataInfo);
        List<String> list = (List<String>) redisDataInfo.getValue();
        for (String s : list) {
            redisTemplate.delete(s);
        }
        redisTemplate.getConnectionFactory().getConnection().close();
    }

    @Override
    public Long deleteAllKey(RedisDataInfo redisDataInfo) {
        return deleteKeys(redisDataInfo, "*");
    }

    @Override
    public Long deleteKeys(RedisDataInfo redisDataInfo, String pattern) {
        StringRedisTemplate redisTemplate = redisService.getRedisTemplate(redisDataInfo);
        Set<String> keys = redisTemplate.keys(pattern);
        Long l = redisTemplate.delete(keys);
        redisTemplate.getConnectionFactory().getConnection().close();
        return l;
    }

    @Override
    public boolean renameKey(RedisDataInfo redisDataInfo, String oldKey, String newKey) {
        StringRedisTemplate redisTemplate = redisService.getRedisTemplate(redisDataInfo);
        try {
            if (redisTemplate.hasKey(newKey)) {
                return false;
            }
            redisTemplate.rename(oldKey, newKey);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            redisTemplate.getConnectionFactory().getConnection().close();
        }
        return true;
    }

}
